https 協議對於開發者而言其實只是多了一步證書驗證的過程,這個證書正常情況下被 jdk/jre/security/cacerts 所管理,裡面證書包含兩種情況:
1、機構所頒發的被認證的證書,這種證書的網站在瀏覽器訪問時 https 頭顯示爲綠色
2、個人所設定的證書,這種證書的網站在瀏覽器裡 https 頭顯示爲紅色 ×,且需要點擊信任該網站才能繼續訪問,。而點擊信任這一步的操作就是我們在 java 代碼訪問 https 網站時區別於 http 請求需要做的事情。
所以 JAVA 發送 https 請求有兩種情況,三種解決辦法:
第一種情況:https 網站的證書爲機構所頒發的被認證的證書,這種情況下和 http 請求一模一樣無需做任何改變,用 HttpsURLConnection 或者 HttpURLConnection 都可以
public static void main(String[] args) throws Exception{
URL serverUrl = new URL("https://xxxx");
HttpURLConnection conn =
(HttpURLConnection) serverUrl.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
conn.setInstanceFollowRedirects(false);
conn.connect();
String result = Sender.getReturn(conn);
}
public static String getReturn(HttpURLConnection connection)
throws Exception{
StringBuffer buffer = new StringBuffer();
try(InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream,
java.lang.invoke.ConstantInfo.CHARSET);
BufferedReader bufferedReader =
new BufferedReader(inputStreamReader);) {
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
String result = buffer.toString();
return result;
}
}
第二種情況:個人所設定的證書,這種證書默認不被信任,需要我們自己選擇信任,信任的辦法有兩種
A、將證書導入java的運行環境中
從該網站下載或者從網站開發者出獲取證書 cacert.crt 運行命令將證書導入 java 運行環境:keytool -import -keystore %JAVA_HOME%\jre\lib\security\cacerts -file cacert.crt -alias xxx
完成,java 代碼中發送 https 的請求和 http 一樣,同第一種情況。
B、忽略證書驗證過程,忽略之後任何 https協議網站皆能正常訪問,同第一種情況
import java.net.URL;
import java.security.cert.*;
import javax.net.ssl.*;
public class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate certificates[],
String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] ax509certificate,
String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
public static void main(String[] args) throws Exception {
SSLContext sc = SSLContext.getInstance("TLSv1.2", "SunJSSE");
sc.init(null,
new TrustManager[] {new MyX509TrustManager() },
new java.security.SecureRandom());
SSLSocketFactory ssf = sc.getSocketFactory();
URL url = new URL("https://xxx.com.tw");
HttpsURLConnection httpsConn =
(HttpsURLConnection) url.openConnection();
HostnameVerifier ignoreHostnameVerifier = new HostnameVerifier() {
public boolean verify(String s, SSLSession sslsession) {
System.out.println(
"WARNING: Hostname is not matched for cert."
);
return true;
}
};
httpsConn.setDefaultHostnameVerifier(ignoreHostnameVerifier);
httpsConn.setDefaultSSLSocketFactory(ssf);
}
C、java 代碼中加載證書,必須使用 HttpsURLConnection 方式,從網站開發者出獲取生成證書的密鑰庫 cacert.keystore
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class MyX509TrustManager implements X509TrustManager {
X509TrustManager sunJSSEX509TrustManager;
MyX509TrustManager() throws Exception {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("cancert.keystore"),
"changeit".toCharArray());
TrustManagerFactory tmf =
TrustManagerFactory.getInstance("SunX509", "SunJSSE");
tmf.init(ks);
TrustManager tms [] = tmf.getTrustManagers();
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
sunJSSEX509TrustManager = (X509TrustManager) tms[i];
return;
}
}
throw new Exception("Couldn't initialize");
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
sunJSSEX509TrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
}
}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {
try {
sunJSSEX509TrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
}
}
public X509Certificate[] getAcceptedIssuers() {
return sunJSSEX509TrustManager.getAcceptedIssuers();
}
}
public static void main(String[] args) throws Exception {
SSLContext sslcontext =
SSLContext.getInstance("SSL","SunJSSE");
sslcontext.init(null, new TrustManager[]{new MyX509TrustManager()},
new java.security.SecureRandom());
URL serverUrl = new URL("https://xxxx");
HttpsURLConnection conn = (HttpsURLConnection) serverUrl.openConnection();
conn.setSSLSocketFactory(sslcontext.getSocketFactory());
conn.setRequestMethod("GET");
conn.setRequestProperty("Content-type", "application/json");
conn.setInstanceFollowRedirects(false);
conn.connect();
String result = getReturn(conn);
}
public static String getReturn(HttpsURLConnection connection)
throws IOException {
StringBuffer buffer = new StringBuffer();
try (InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream,
ConstantInfo.CHARSET);
BufferedReader bufferedReader =
new BufferedReader(inputStreamReader);
)
{
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
String result = buffer.toString();
return result;
}
}